﻿using System;
using System.Reflection;
using Birkelund.QueryStrings.Internals;
using NUnit.Framework;
using Birkelund.QueryStrings.Tokens;

namespace Birkelund.QueryStrings.Test
{
    public class QueryStringTokenBaseTest
    {
        [Test]
        public void ValidKey()
        {
            var a = new TestToken("keyName");
            Assert.AreEqual("keyName", a.KeyName);
            Assert.IsNull(a.DefaultValue);
            Assert.IsNull(a.ReadFailureAction);
            Assert.IsNull(a.Validator);
            Assert.AreEqual(ExceptionNotificationBehaviour.ThrowException, a.ExceptionNotificationBehaviour);
        }

        [Test]
        public void ValidKey_MaxAllowedLength()
        {
            BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;
            FieldInfo field = typeof(QueryStringTokenBase<>).GetField("MAX_KEY_LENGTH", flags);
            int MAX_KEY_LENGTH = Convert.ToInt32(field.GetValue(null));

            string longString = "abcdefghijklmnopqrstuwvxyzabcdefghijklmnopqrstuwvxyzabcdefghijklmnopqrstuwvxyzabcdefghijklmnopqrstuwvxyz";
            string keyName = longString.Substring(0, MAX_KEY_LENGTH);
            var A = new TestToken(keyName);
            Assert.Pass();
        }

        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void InvalidKey_Empty()
        {
            var A = new TestToken(string.Empty);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void InvalidKey_Null()
        {
            var A = new TestToken(null);
        }

        [Test]
        public void InvalidKey_PositiveTest([Values("mykey")] string candidate)
        {
            var a = new TestToken(candidate);
        }

        [Test]
        public void InvalidKey_PositiveTest_WithFullEncryptionKey()
        {
            var a = new TestToken(FullEncryptionKeyToken.Instance.KeyName);
        }

        [Test]
        public void InvalidKey_NegativeTest(
            [Values(
                "my&key",
                "my@key",
                "myækey",
                "myøkey",
                "myÅkey",
                "my=key",
                "my?key",
                "my+key",
                "my'key",
                "my key",
                "my_key",
                "my-key",
                "thisIsTheNameOfAVeryLongKey", //way too long
                "elevenChars" // one char too long
                )]
            string candidate)
        {
            try
            {
                new TestToken(candidate);
                Assert.Fail("InvalidKey: " + candidate);
            }
            catch (ArgumentException)
            {
                Assert.Pass();
            }
        }

        [Test]
        public void InvalidKey_NegativeTest_WithCheckSum()
        {
            try
            {
                new TestToken(CheckSumKeyToken.Instance.KeyName);
                Assert.Fail("InvalidKey: " + CheckSumKeyToken.Instance.KeyName);
            }
            catch (ArgumentException)
            {
                Assert.Pass();
            }
        }

        [Test]
        public void ReadValue_WrongCasing()
        {
            Uri initialUrl = new Uri(@"http://localhost/test/testFile.aspx?test=68");
            int expected = 68;
            IQueryStringToken<int> token = new ValueTypeToken<int>("TEST");
            Assert.AreEqual(expected, token.ReadValue(initialUrl));
        }

        [Test]
        public void TryReadValueTest()
        {
            Uri initialUrl = new Uri(@"https://localhost/test/testFile.aspx");
            var a = new TestToken("id")
            {
                ExceptionNotificationBehaviour = ExceptionNotificationBehaviour.ThrowException
            };

            string res;
            bool canRead = a.TryReadValue(initialUrl, out res, ReadValueMode.NoCheckSumControl);

            Assert.IsFalse(canRead);
        }

        [Test]
        public void ExistsTest()
        {
            Uri initialUrl = new Uri("http://localhost/test/testFile.aspx?a=123");
            IQueryStringToken<int> token = new ValueTypeToken<int>("a");

            Assert.IsTrue(token.Exists(initialUrl));
        }

        private class TestToken : QueryStringTokenBase<string> //Type doesn't matter as that's not what we test
        {
            public TestToken(string keyName)
                : base(keyName)
            {
            }

            protected override string OnParseFromString(string stringValue)
            {
                throw new NotImplementedException(); //no need to implement this method in this context
            }

            protected override string OnRenderTokenValue(string value)
            {
                throw new NotImplementedException();
            }
        }
    }
}
